package com.bbva.kyfb.kyfbbofc.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.bbva.jee.arq.spring.core.gce.CodigoError;
import com.bbva.jee.arq.spring.core.gce.ExcepcionEjecucionAplicacion;
import com.bbva.kyfb.kyfbbofc.IHistoricoBo;
import com.bbva.kyfb.kyfbbofc.converters.DtoToDtoBofcConverter;
import com.bbva.kyfb.kyfbdaofc.IHistoricoDao;
import com.bbva.kyfb.kyfbdto.firmas.bo.Auditoria;
import com.bbva.kyfb.kyfbdto.firmas.bo.FicheroConfeccion;
import com.bbva.kyfb.kyfbdto.firmas.bo.FicheroEstadoIntermedioDto;
import com.bbva.kyfb.kyfbdto.firmas.bo.FicheroInfo;
import com.bbva.kyfb.kyfbdto.firmas.errores.Errores_kyfb_servicios;
import com.bbva.kyfb.kyfbdto.firmas.filtros.FiltroFicheros;
import com.bbva.kyfb.kyfbdto.firmas.sistemasHost.ConsultaSituacionFicherosOutDto;
import com.bbva.kyfb.kyfbjpatlbh.dominiotlbh.Ttlsbfua;
import com.bbva.kyfb.kyfbutils.constantes.ConstantesFO;
import com.bbva.kyfb.kyfbutils.constantes.UtilFO;
import com.bbva.kyfb.kyfbutils.dao.DaoUtils;

/**
 * The Class ServicioHistoricoBoImpl.
 */
@Component
public class ServicioHistoricoBoImpl implements IHistoricoBo {

	/** The servicio historico dao. */
	@Autowired
	private IHistoricoDao servicioHistoricoDao;

	/** The servicio historico bo host util. */
	@Autowired
	private ServicioHistoricoBoHostUtil servicioHistoricoBoHostUtil;

	/** Los errores de Tx no cortan carga de listas por query */
	private CodigoError errorPorTx;

	//** The servicio firmas bo util. */
	//	@Autowired
	//private ServicioFirmasInvokerComun servicioFirmasInvokerComun;

	/** {@inheritDoc}
	 * @see com.bbva.kyfb.kyfbbofc.IHistoricoBo#getComponentesHistoricoReferencia(com.bbva.kyfb.kyfbdto.firmas.bo.FicheroInfo)
	 */
	@Override
	public List<FicheroConfeccion> getComponentesHistoricoReferencia(final FicheroInfo file) {
		final FiltroFicheros filtro  = createFiltroFromDto(file);
		List<FicheroConfeccion> listaFicherosHost = new ArrayList<FicheroConfeccion>();

		/*PENDIENTE DE FUNCIONAMIENTO DE invoker listarRelProdEmpresa
		String canal = file.getCodClienteCash().substring(0,4);
		String bancoInt = file.getCodClienteCash().substring(4,8);
		String ref = file.getCodClienteCash().substring(8);*/

		//		List<ReferenciaInfo> listaRefsRel= servicioFirmasInvokerComun.getEmpresas(canal, bancoInt, ref);

		try{
			ConsultaSituacionFicherosOutDto respuestaHost;
//			int i=-1;
//			do{		
//				if(i!=-1){
//					ReferenciaInfo refInfo = listaRefsRel.get(i);
//					file.setsReferencia(refInfo.getReferencia());
//				}
				respuestaHost = servicioHistoricoBoHostUtil.getConsultaSituacionFicheros(file);
				if(respuestaHost!=null){
					listaFicherosHost.addAll(DtoToDtoBofcConverter.listaFicheroDtoTolistaFicheroConfeccion(respuestaHost.getListaFicheros()));
				}
				
				errorPorTx = Errores_kyfb_servicios.OK;
//				i++;
//			}while(i<listaRefsRel.size());	
		}catch(ExcepcionEjecucionAplicacion ea){
			if(isErrorTxNoBloqueante(ea.getCodigoError())){
				errorPorTx = ea.getCodigoError();
			}else{
				throw ea;
			}
		}

		List<FicheroConfeccion> listaFicherosFS = createFicheroConfDtoFromEntity(servicioHistoricoDao.findHistoricoReferencia(file.getCodClienteCash(), filtro, null, filtro.getCodUsuario() != null));

		//Actualiza divisa en lista FS
		listaFicherosFS = cambiarDivisas(listaFicherosFS);
		//Actualiza divisa en lista host
		listaFicherosHost = cambiarDivisas(listaFicherosHost);

		final List<FicheroConfeccion> listaFicherosFiltradosHost = filtrarFicherosHost(listaFicherosHost,file);

		//Fusionamos las listas
		final List<FicheroConfeccion> listaFicherosRdo = new ArrayList<FicheroConfeccion>();
		listaFicherosRdo.addAll(listaFicherosFS);
		listaFicherosRdo.addAll(listaFicherosFiltradosHost);

		final Map<String,Integer> mapContFicheros = servicioHistoricoBoHostUtil.getMapaContadorFicheros(listaFicherosHost);

		final Date fechaDeHoy = new Date();

		final Date fechaDesde = file.getsTipoFecha()!=null?filtro.getFechaCreacionDesde():filtro.getFechaProcesoDesde();
		final Date fechaHasta = file.getsTipoFecha()!=null?filtro.getFechaCreacionHasta():filtro.getFechaProcesoHasta();

		//La lista de Estados intermedios solo se mezcla si la fecha actual entra en el rango de fechas solicitado
		if(fechaDesde!=null && fechaHasta!=null && fechaDeHoy.getTime()>=fechaDesde.getTime() && fechaDeHoy.getTime()<=fechaHasta.getTime()){

			List<FicheroEstadoIntermedioDto> listaFicherosEI = createFicheroEIDtoFromEntity(servicioHistoricoDao.findHistoricoReferenciaEstadosIntermedios(file.getCodClienteCash(), filtro, filtro.getCodUsuario() != null));
			listaFicherosEI = servicioHistoricoBoHostUtil.filtrarEIPorHost(listaFicherosEI,mapContFicheros);

			if(!listaFicherosEI.isEmpty()){
				final List<FicheroConfeccion> listaFicherosConfEI = createFicheroConfDtoFromEntity(servicioHistoricoDao.findHistoricoReferencia(file.getCodClienteCash(), filtro, getListaNumItemsFicherosEI(listaFicherosEI), filtro.getCodUsuario() != null));
				listaFicherosRdo.addAll(listaFicherosConfEI);
			}
		}

		DaoUtils.atLeastOneRecord(listaFicherosRdo);

		return listaFicherosRdo;
	}

	private List<FicheroConfeccion> cambiarDivisas(final List<FicheroConfeccion> listaFicheros){
		final List<FicheroConfeccion> listaFicherosNuevaDivisa = new ArrayList<FicheroConfeccion>();

		for(final FicheroConfeccion fc:listaFicheros){
			if(fc.getsDivisa()==null){
				if(ConstantesFO.PAGOS_INT_ESPANA.equals(fc.getsCodTipoOrden())) {
					fc.setsDivisa(ConstantesFO.MULTIDIVISA);
				} else {
					fc.setsDivisa(ConstantesFO.VACIO);
				}
			}
			listaFicherosNuevaDivisa.add(fc);
		}

		return listaFicherosNuevaDivisa;
	}

	private List<FicheroConfeccion> filtrarFicherosHost(List<FicheroConfeccion> listaFicheros,final FicheroInfo file){
		final List<FicheroConfeccion> aux = new ArrayList<FicheroConfeccion>();
		String divisas=null;
		String estados=null;
		String tipoOrdenes=null;
		BigDecimal importeDesde = null;
		BigDecimal importeHasta = null;

		if(file.getsDivisa()!=null){
			final String[] divisasFiltro = file.getsDivisa();
			divisas = StringUtils.join(divisasFiltro,"|");
		}

		if(file.getsCodEstado()!=null){
			final String[] estadoFiltro = file.getsCodEstado();
			estados = StringUtils.join(estadoFiltro,"|");
		}

		if(file.getsTipoOrden()!=null){
			final String[] ordenFiltro = file.getsTipoOrden();
			tipoOrdenes = StringUtils.join(ordenFiltro,"|");
		}

		if(file.getsImporteDesde()!=null){
			importeDesde = new BigDecimal(file.getsImporteDesde());
		}

		if(file.getsImporteHasta()!=null){
			importeHasta = new BigDecimal(file.getsImporteHasta());
		}

		boolean pendientesFiltrados = false;

		if(divisas!=null || estados!=null && !"TO".equals(estados) || tipoOrdenes!=null || importeHasta!=null || importeDesde!=null){
			for(final FicheroConfeccion fc:listaFicheros) {
				final String estadoHost = fc.getsCodEstadoFichero();

				if((divisas==null || divisas.indexOf(fc.getsDivisa())!=-1)
						&& (estados==null || "TO".equals(estados) || !StringUtils.isEmpty(estadoHost)&& estados.indexOf(estadoHost)!=-1)
						&& (tipoOrdenes==null || tipoOrdenes.indexOf(fc.getsCodTipoOrden())!=-1)
						&& (importeDesde==null || fc.getdImporte().compareTo(importeDesde)>-1)
						&& (importeHasta==null || fc.getdImporte().compareTo(importeHasta)<1)
						&& !servicioHistoricoBoHostUtil.isEstadoHostPendiente(fc)){
					aux.add(fc);
				}
			}
			pendientesFiltrados = true;
			listaFicheros = aux;
		}

		if(!pendientesFiltrados && ConstantesFO.SIGLAS_FIRMA_HOST.equals(file.getStipoFirma())){
			for(final FicheroConfeccion fc:listaFicheros) {
				if(!servicioHistoricoBoHostUtil.isEstadoHostPendiente(fc)){
					aux.add(fc);
				}
			}
			listaFicheros = aux;
		}

		return listaFicheros;
	}

	/**
	 * Devuelve lista de numItems para Ficheros de estados intermedios
	 * @param List<FicheroEstadoIntermedioDto> listaFicherosEI
	 * @return Long[] numItems
	 */
	private Long[] getListaNumItemsFicherosEI(final List<FicheroEstadoIntermedioDto> listaFicherosEI){
		final Long numItems[] = new Long[listaFicherosEI.size()];
		int i=0;

		for(final FicheroEstadoIntermedioDto fei:listaFicherosEI){
			numItems[i++]=fei.getsNumItem();
		}

		return numItems;
	}

	/** {@inheritDoc}
	 * @see com.bbva.kyfb.kyfbbofc.IHistoricoBo#getAuditoriaComponenteHistorico(com.bbva.kyfb.kyfbdto.firmas.bo.FicheroInfo)
	 */
	@Override
	public List<Auditoria> getAuditoriaComponenteHistorico(final FicheroInfo file) {
		return createAuditoriaDtoFromEntity(servicioHistoricoDao.findAuditoriaComponenteHistorico(file.getCodClienteCash(), file.getsTipoOrden()[0], file.getIdOrden(), file.getsCodEstado()));
	}

	/**
	 * Creates the filtro from dto.
	 *
	 * @param file the file
	 * @return the filtro ficheros
	 */
	private FiltroFicheros createFiltroFromDto(final FicheroInfo file) {
		FiltroFicheros filtro = null;
		try {
			if (file != null) {
				filtro = new FiltroFicheros();
				if (file.getsCodEstado() != null) {
					//TODO: MAPEAR ESTADOS Y CONSTANTES. METODO ESTATICO EN EL UTILS
					final String[] estadosSigla = new String[file.getsCodEstado().length];

					for(int i=0; i<file.getsCodEstado().length;i++){
						final String estadoNum = file.getsCodEstado()[i];
						estadosSigla[i] = UtilFO.getCodSigla(estadoNum);
					}
					filtro.setEstados(estadosSigla);
				}
				if (file.getsDivisa() != null) {
					filtro.setDivisas(file.getsDivisa());
				}
				if (UtilFO.FECHA_CREACION.equals(file.getsTipoFecha())) {
					if (file.getsFechaDesde() != null) {
						filtro.setFechaCreacionDesde(file.getsFechaDesde());
					}
					if (file.getsFechaHasta() != null) {
						filtro.setFechaCreacionHasta(file.getsFechaHasta());
					}

				} else if(!UtilFO.ESTADOS_TODOS.equals(file.getsTipoFecha())){ // La que se pone por defecto.
					if (file.getsFechaDesde() != null) {
						filtro.setFechaProcesoDesde(file.getsFechaDesde());
					}
					if (file.getsFechaHasta() != null) {
						filtro.setFechaProcesoHasta(file.getsFechaHasta());
					}
				} else {
					if (file.getsFechaDesde() != null) {
						filtro.setFechaCreacionDesde(file.getsFechaDesde());
					}
					if (file.getsFechaHasta() != null) {
						filtro.setFechaCreacionHasta(file.getsFechaHasta());
					}
					if (file.getsFechaDesde() != null) {
						filtro.setFechaProcesoDesde(file.getsFechaDesde());
					}
					if (file.getsFechaHasta() != null) {
						filtro.setFechaProcesoHasta(file.getsFechaHasta());
					}
				}


				if (file.getsImporteDesde() != null) {
					filtro.setImporteDesde(file.getsImporteDesde());
				}
				if (file.getsImporteHasta() != null) {
					filtro.setImporteHasta(file.getsImporteHasta());
				}
				if (file.getsTipoOrden() != null) {
					filtro.setClaseOrden(file.getsTipoOrden());
				}
				if (file.getsUsuarioOrdenante() != null) {
					filtro.setCodUsuario(file.getsUsuarioOrdenante());
				}
				if (file.getIdOrden() != null) {
					filtro.setIdOrden(file.getIdOrden());
				}
				filtro.setOrdenarPor(UtilFO.getCampoOrden(file.getsValorOrdenacion(), ConstantesFO.PET_HISTORICO));
				if (file.getsModoOrdenacion() != null) {
					filtro.setModoOrdenacion(file.getsModoOrdenacion());
				}
				if (file.getsPaginacionDesde() != 0) {
					filtro.setPaginarDesde(file.getsPaginacionDesde());
				}
				if (file.getsPaginacionNumElementos() != 0) {
					filtro.setNumElementos(file.getsPaginacionNumElementos());
				}
			}
		} catch (final Exception e) {
			throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.FORMATO_INCORRECTO,e);
		}
		return filtro;
	}

	/**
	 * Creates the fichero estado intermedio dto from entity.
	 *
	 * @param entidades the entidades
	 * @return the list
	 */
	private List<FicheroEstadoIntermedioDto> createFicheroEIDtoFromEntity(final List<Object[]> entidades)
	{
		final ArrayList<FicheroEstadoIntermedioDto> fichEI = new ArrayList<FicheroEstadoIntermedioDto>();
		final SimpleDateFormat ss = new SimpleDateFormat("yyyyMMdd");

		try {
			//			Entidad desde BBDD:
			//			B.QNU_NUMITEM AS QNU_NUMITEM
			//			B.COD_LOGONAPL AS COD_LOGONAPL
			//			B.FEC_RECEPCIO AS FEC_RECEPCIO
			//			I.DES_NOMBRE AS DES_NOMBRE
			//			I.COD_COMREFEX AS COD_COMREFEX

			for (final Object[] o : entidades) {
				int i=0;

				final FicheroEstadoIntermedioDto fichero = new FicheroEstadoIntermedioDto();
				fichero.setsNumItem(((BigDecimal) o[i]).longValue());
				fichero.setCodLogon(((String) o[++i]).trim());
				fichero.setdFechaProceso(ss.parse(((String) o[++i]).trim()));
				fichero.setsNombreFichero(((String) o[++i]).trim());
				fichero.setTipoOrden(((String) o[++i]).trim().substring(1));	//.TIN -> TipoOrden = TIN

				fichEI.add(fichero);
			}
		} catch (final Exception e) {
			throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.ERROR_FORMATEO_RESPUESTA, e);
		}
		return fichEI;
	}

	/**
	 * Creates the fichero conf dto from entity.
	 *
	 * @param entidades the entidades
	 * @return the list
	 */
	private List<FicheroConfeccion> createFicheroConfDtoFromEntity(final List<Object[]> entidades)
	{
		final ArrayList<FicheroConfeccion> fichConf = new ArrayList<FicheroConfeccion>();
		final SimpleDateFormat ss = new SimpleDateFormat("yyyyMMdd");

		try {
			//			"C.DES_NOMFICH, C.FEC_PROCESCA, C.QNU_TOTREGIS, C.QTY_TOTIMP,"+
			//			"C.COD_ESTACASH, C.COD_CLASEORD, C.COD_IDORDEN, O.DES_CUENORIG,D.COD_ABREVIAT "+
			int i;
			FicheroConfeccion fichero;
			for (final Object[] o : entidades) {
				fichero = new FicheroConfeccion();
				i = 0;
				fichero.setsNombreFichero(((String) o[i]).trim());
				fichero.setdFechaProceso(ss.parse(((String) o[++i]).trim()));
				fichero.setiNumeroOrdenes((Integer) o[++i]);
				fichero.setdImporte((BigDecimal) o[++i]);
				//TODO: mapear a constante para FRONT. Metodo en UTIL
				fichero.setsCodEstadoFichero(((String) o[++i]).trim());
				fichero.setsCodTipoOrden(((String) o[++i]).trim());
				fichero.setsIdOrdenFirmas(((String) o[++i]).trim());
				i++;
				if (o[i] != null) {
					fichero.setsAsunto(((String) o[i]).trim());
				}
				fichero.setsDivisa(((String) o[++i]).trim());
				fichero.setModoOrden((String) o[++i]);
				i++;
				if (o[i] != null) {
					// 08.10.2013: Al ser LEFT JOIN, la fecha puede venir con valores nulos
					fichero.setdFechaCreacion((Date) o[i]);
				}
				fichConf.add(fichero);
			}
		} catch (final Exception e) {
			throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.ERROR_FORMATEO_RESPUESTA, e);
		}
		return fichConf;
	}

	/**
	 * Creates the auditoria dto from entity.
	 *
	 * @param listFua the list fua
	 * @return the list
	 */
	private List<Auditoria> createAuditoriaDtoFromEntity(final List<Ttlsbfua> listFua)
	{
		final ArrayList<Auditoria> listaAuditoria = new ArrayList<Auditoria>();
		final SimpleDateFormat ss = new SimpleDateFormat("yyyyMMdd HHmmssSS");

		try {
			for (final Ttlsbfua fua : listFua) {
				final Auditoria auditoria = new Auditoria();
				//TODO: Peso no disponible
				//auditoria.setdPesoOrden(fua.get);
				//TODO MAPEAR ACCIONES
				auditoria.setsCodAccion(fua.getId().getCodAccion());
				//TODO MAPEAR Estados
				auditoria.setsCodEstado(fua.getCodEstadfic().trim());
				auditoria.setsCodUsuario(fua.getCodUsuario().trim());
				auditoria.setsCodUsuarioFirma(fua.getCodUsufirma().trim());
				auditoria.setsFechaAccion(ss.parse(fua.getFecAccio().trim()+" "+fua.getFecAccion2().trim()));
				auditoria.setsPoderUsuarioFirmante(fua.getCodUsupoder().trim());
				listaAuditoria.add(auditoria);
			}
		} catch (final Exception e) {
			throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.ERROR_FORMATEO_RESPUESTA, e);
		}
		return listaAuditoria;
	}

	/**
	 * Gets the servicio historico dao.
	 *
	 * @return the servicio historico dao
	 */
	public IHistoricoDao getServicioHistoricoDao() {
		return servicioHistoricoDao;
	}

	/**
	 * Sets the servicio historico dao.
	 *
	 * @param servHistoricoDao the new servicio historico dao
	 */
	public void setServicioHistoricoDao(final IHistoricoDao servHistoricoDao) {
		this.servicioHistoricoDao = servHistoricoDao;
	}

	@Override
	public CodigoError getErrorPorTx(){
		return errorPorTx;
	}

	private boolean isErrorTxNoBloqueante(final CodigoError error){
		return error.equals(Errores_kyfb_servicios.ERROR_AL_LANZAR_TX_DEMASIADAS_RESPUESTAS) ||
				error.equals(Errores_kyfb_servicios.ERROR_AL_LANZAR_TX_ERROR_EN_BBDD) ||
				error.equals(Errores_kyfb_servicios.ERROR_AL_LANZAR_TX_INFORMACION_INEXISTENTE);
	}

	/* Metodos que ya no se usan

	/**
	 * Creates the fichero estado intermedio dto from entity.
	 *
	 * @param entidades the entidades
	 * @return the list
	 *
	private List<FicheroEstadoIntermedioDto> createFicheroEIDtoFromEntity(final List<Object[]> entidades)
	{
		final ArrayList<FicheroEstadoIntermedioDto> fichEI = new ArrayList<FicheroEstadoIntermedioDto>();
		final SimpleDateFormat ss = new SimpleDateFormat("yyyyMMdd");

		try {
			//			Entidad desde BBDD:
			//			B.QNU_NUMITEM AS QNU_NUMITEM
			//			B.COD_LOGONAPL AS COD_LOGONAPL
			//			B.FEC_RECEPCIO AS FEC_RECEPCIO
			//			I.DES_NOMBRE AS DES_NOMBRE
			//			I.COD_COMREFEX AS COD_COMREFEX

			for (final Object[] o : entidades) {
				int i=0;

				final FicheroEstadoIntermedioDto fichero = new FicheroEstadoIntermedioDto();
				fichero.setsNumItem(((BigDecimal) o[i]).longValue());
				fichero.setCodLogon(((String) o[++i]).trim());
				fichero.setdFechaProceso(ss.parse(((String) o[++i]).trim()));
				fichero.setsNombreFichero(((String) o[++i]).trim());
				fichero.setTipoOrden(((String) o[++i]).trim().substring(1));	//.TIN -> TipoOrden = TIN

				fichEI.add(fichero);
			}
		} catch (final Exception e) {
			throw new ExcepcionEjecucionAplicacion(Errores_kyfb_servicios.ERROR_FORMATEO_RESPUESTA, e);
		}
		return fichEI;
	}



	/**
	 * Devuelve lista de numItems para Ficheros de estados intermedios
	 * @param List<FicheroEstadoIntermedioDto> listaFicherosEI
	 * @return Long[] numItems
	 *
	private Long[] getListaNumItemsFicherosEI(final List<FicheroEstadoIntermedioDto> listaFicherosEI){
		final Long numItems[] = new Long[listaFicherosEI.size()];
		int i=0;

		for(final FicheroEstadoIntermedioDto fei:listaFicherosEI){
			numItems[i++]=fei.getsNumItem();
		}

		return numItems;
	}

	 */
}
